"""
@Author: li
@Email: lijianqiao2906@live.com
@FileName: user.py
@DateTime: 2025/07/05
@Docs: 用户相关DAO层 - User、Role、Permission、Menu
"""

from typing import TYPE_CHECKING

from app.dao.base import BaseDAO
from app.utils.logger import logger

if TYPE_CHECKING:
    from app.models.user import Menu, Permission, Role, User
else:
    from app.models.user import Menu, Permission, Role, User


class UserDAO(BaseDAO):
    """用户DAO类"""

    def __init__(self):
        super().__init__(User)

    async def get_by_username(self, username: str) -> User | None:
        """根据用户名获取用户"""
        result = await self.get_one(username=username)
        return result if isinstance(result, User) else None

    async def get_by_email(self, email: str) -> User | None:
        """根据邮箱获取用户"""
        result = await self.get_one(email=email)
        return result if isinstance(result, User) else None

    async def get_by_phone(self, phone: str) -> User | None:
        """根据手机号获取用户"""
        result = await self.get_one(phone=phone)
        return result if isinstance(result, User) else None

    async def exists_by_username(self, username: str) -> bool:
        """检查用户名是否存在"""
        return await self.exists(username=username)

    async def exists_by_email(self, email: str) -> bool:
        """检查邮箱是否存在"""
        return await self.exists(email=email)

    async def exists_by_phone(self, phone: str) -> bool:
        """检查手机号是否存在"""
        return await self.exists(phone=phone)

    async def get_with_roles(self, user_id: int) -> User | None:
        """获取用户及其角色信息"""
        try:
            return await User.get_or_none(id=user_id).prefetch_related("roles")
        except Exception:
            return None

    async def get_superusers(self) -> list[User]:
        """获取所有超级管理员"""
        results = await self.get_active_all(is_superuser=True)
        return [result for result in results if isinstance(result, User)]

    async def update_last_login(self, user_id: int) -> bool:
        """更新用户最后登录时间"""
        from datetime import datetime

        try:
            count = await self.update_by_id(user_id, last_login_at=datetime.now())
            return count is not None
        except Exception:
            return False

    async def update_password(self, user_id: int, new_password: str) -> bool:
        """更新用户密码"""
        try:
            # 这里应该对密码进行哈希处理，但现在仅演示DAO功能
            user = await self.get_by_id(user_id)
            if user:
                user.password = new_password  # 实际应用中需要哈希处理
                await user.save()
                return True
            return False
        except Exception as e:
            logger.error(f"更新用户密码失败: {e}")
            return False


class RoleDAO(BaseDAO):
    """角色DAO类"""

    def __init__(self):
        super().__init__(Role)

    async def get_by_code(self, code: str) -> Role | None:
        """根据角色编码获取角色"""
        result = await self.get_one(code=code)
        return result if isinstance(result, Role) else None

    async def exists_by_code(self, code: str) -> bool:
        """检查角色编码是否存在"""
        return await self.exists(code=code)

    async def get_with_permissions(self, role_id: int) -> Role | None:
        """获取角色及其权限信息"""
        try:
            return await Role.get_or_none(id=role_id).prefetch_related("permissions")
        except Exception:
            return None

    async def get_by_sort_order(self) -> list[Role]:
        """按排序获取所有角色"""
        try:
            return await Role.filter(is_active=True, is_deleted=False).order_by("sort_order", "created_at").all()
        except Exception:
            return []

    async def assign_permissions(self, role_id: int, permission_ids: list[int]) -> bool:
        """为角色分配权限"""
        try:
            role = await Role.get_or_none(id=role_id)
            if not role:
                return False

            permissions = await Permission.filter(id__in=permission_ids).all()
            await role.permissions.clear()
            await role.permissions.add(*permissions)
            return True
        except Exception:
            return False


class PermissionDAO(BaseDAO):
    """权限DAO类"""

    def __init__(self):
        super().__init__(Permission)

    async def get_by_code(self, code: str) -> Permission | None:
        """根据权限编码获取权限"""
        result = await self.get_one(code=code)
        return result if isinstance(result, Permission) else None

    async def exists_by_code(self, code: str) -> bool:
        """检查权限编码是否存在"""
        return await self.exists(code=code)

    async def get_tree_structure(self) -> list[Permission]:
        """获取权限树形结构"""
        try:
            return await Permission.filter(is_active=True, is_deleted=False).order_by("sort_order", "created_at").all()
        except Exception:
            return []

    async def get_by_parent_id(self, parent_id: int | None = None) -> list[Permission]:
        """根据父ID获取子权限"""
        results = await self.get_active_all(parent_id=parent_id)
        return [result for result in results if isinstance(result, Permission)]

    async def get_by_type(self, permission_type: str) -> list[Permission]:
        """根据权限类型获取权限"""
        results = await self.get_active_all(type=permission_type)
        return [result for result in results if isinstance(result, Permission)]

    async def get_by_resource(self, resource: str) -> list[Permission]:
        """根据资源标识获取权限"""
        results = await self.get_active_all(resource=resource)
        return [result for result in results if isinstance(result, Permission)]


class MenuDAO(BaseDAO):
    """菜单DAO类"""

    def __init__(self):
        super().__init__(Menu)

    async def get_tree_structure(self) -> list[Menu]:
        """获取菜单树形结构"""
        try:
            return await Menu.filter(is_active=True, is_deleted=False).order_by("sort_order", "created_at").all()
        except Exception:
            return []

    async def get_by_parent_id(self, parent_id: int | None = None) -> list[Menu]:
        """根据父ID获取子菜单"""
        results = await self.get_active_all(parent_id=parent_id)
        return [result for result in results if isinstance(result, Menu)]

    async def get_by_type(self, menu_type: str) -> list[Menu]:
        """根据菜单类型获取菜单"""
        results = await self.get_active_all(type=menu_type)
        return [result for result in results if isinstance(result, Menu)]

    async def get_visible_menus(self) -> list[Menu]:
        """获取可见菜单（非隐藏）"""
        results = await self.get_active_all(is_hidden=False)
        return [result for result in results if isinstance(result, Menu)]

    async def get_by_permission_code(self, permission_code: str) -> list[Menu]:
        """根据权限编码获取菜单"""
        results = await self.get_active_all(permission_code=permission_code)
        return [result for result in results if isinstance(result, Menu)]

    async def get_user_menus(self, user_id: int) -> list[Menu]:
        """获取用户可访问的菜单"""
        try:
            # 首先获取用户的角色
            user = await User.get_or_none(id=user_id).prefetch_related("roles__permissions")
            if not user:
                return []

            # 获取用户所有权限编码
            permission_codes = set()
            for role in user.roles:
                for permission in role.permissions:
                    permission_codes.add(permission.code)

            # 获取对应的菜单
            if permission_codes:
                menus = (
                    await Menu.filter(
                        is_active=True, is_deleted=False, is_hidden=False, permission_code__in=list(permission_codes)
                    )
                    .order_by("sort_order", "created_at")
                    .all()
                )
                return menus
            return []
        except Exception:
            return []


# 创建DAO实例
user_dao = UserDAO()
role_dao = RoleDAO()
permission_dao = PermissionDAO()
menu_dao = MenuDAO()
